import { Injectable, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common';
import { RedisService as NestRedisService } from '@liaoliaots/nestjs-redis';
import type { Redis } from 'ioredis';

@Injectable()
export class RedisService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(RedisService.name);
  private heartbeatInterval: NodeJS.Timeout;
  private redis: Redis;

  constructor(
    private readonly redisService: NestRedisService,
  ) {
    this.redis = this.redisService.getOrThrow();
  }

  async onModuleInit() {
    // 设置 Redis 连接事件监听
    this.setupEventListeners();

    // 启动心跳检查
    this.startHeartbeat();
  }

  async onModuleDestroy() {
    // 清理心跳检查
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
    }

    // 关闭 Redis 连接
    if (this.redis) {
      await this.redis.quit();
    }
  }

  private setupEventListeners() {
    this.redis.on('connect', () => {
      this.logger.log('Redis 连接已建立');
    });

    this.redis.on('ready', () => {
      this.logger.log('Redis 连接就绪');
    });

    this.redis.on('error', (err) => {
      this.logger.error(`Redis 连接错误: ${err.message}`, err.stack);
    });

    this.redis.on('close', () => {
      this.logger.warn('Redis 连接已关闭');
    });

    this.redis.on('reconnecting', (time) => {
      this.logger.log(`Redis 正在重连... (${time}ms)`);
    });

    this.redis.on('end', () => {
      this.logger.warn('Redis 连接已结束');
    });
  }

  private startHeartbeat() {
    // 每 30 秒发送一次心跳
    this.heartbeatInterval = setInterval(async () => {
      try {
        await this.redis.ping();
        this.logger.debug('Redis 心跳正常');
      } catch (error) {
        this.logger.warn(`Redis 心跳失败: ${error.message}`);
      }
    }, 30000);
  }

  // 提供一个通用的 Redis 客户端访问方法
  getClient(): Redis {
    return this.redis;
  }

  // 包装常用的 Redis 操作，增加错误处理
  async get(key: string): Promise<string | null> {
    try {
      return await this.redis.get(key);
    } catch (error) {
      this.logger.error(`Redis GET 操作失败，key: ${key}`, error.stack);
      throw error;
    }
  }

  async set(key: string, value: string, ttl?: number): Promise<'OK'> {
    try {
      if (ttl) {
        return await this.redis.setex(key, ttl, value);
      }
      return await this.redis.set(key, value);
    } catch (error) {
      this.logger.error(`Redis SET 操作失败，key: ${key}`, error.stack);
      throw error;
    }
  }

  async del(key: string): Promise<number> {
    try {
      return await this.redis.del(key);
    } catch (error) {
      this.logger.error(`Redis DEL 操作失败，key: ${key}`, error.stack);
      throw error;
    }
  }

  async exists(key: string): Promise<number> {
    try {
      return await this.redis.exists(key);
    } catch (error) {
      this.logger.error(`Redis EXISTS 操作失败，key: ${key}`, error.stack);
      throw error;
    }
  }

  async ttl(key: string): Promise<number> {
    try {
      return await this.redis.ttl(key);
    } catch (error) {
      this.logger.error(`Redis TTL 操作失败，key: ${key}`, error.stack);
      throw error;
    }
  }
}
